import * as XLSX from 'xlsx-js-style';

/**
 * 获取 column的xlsxData Hooks
 * @param columns
 * @returns {*[]}
 */
function useHeaderByColumns(columns) {
  return [columns.map((v) => v.title)];
}

/**
 * 获取dataSource的 xlsxData Hooks
 * @param data
 * @returns {*[]}
 */
function useBodyByDataSource(data) {
  const res = [];
  // eslint-disable-next-line no-unused-vars
  for (const elData of data) {
    const elArr = [];
    // eslint-disable-next-line guard-for-in,no-unused-vars
    for (const elKey in elData) {
      const value = elData[elKey];
      elArr.push(value);
    }
    res.push(elArr);
  }
  return res;
}

/**
 * 获取指定长度的空字符串数组Hooks
 * @param length
 * @returns {string[]}
 */
function useEmptyLine(length) {
  return Array.from({ length }, () => '');
}

/**
 * @description 导出一个工作表内多个table
 * @define sheet：工作表名；sheetBody：{ type===1: 传column,dataSource; type===2: 传dataSource,groupedHeader<2d数组>; type===3: 传anyXlsxData<2d数组>}
 * @define columnWidth：列宽，索引+1代表列数；mergeRules：s为开始单元格，e为结束位置，r是row，表示行号，c是col，表示列号，从 0 计起
 * @define callback：接受工作表对象，返回工作表对象，更多样式设置见https://blog.csdn.net/FE_dev/article/details/106396416
 * @param sheetConfig { { sheet: {
 *   sheetBody: { type: number, columns: [], dataSource: [], groupedHeader: Array[], anyXlsxData: Array[] }[],
 *   columnWidth?: { wpx: number }[],
 *   mergeRules?: { s: {r: number, c: number}, e: {r: number, c: number} }[],
 *   callback?: (wb) => wb,
 *  } } }
 * @param filename { string } 文件名
 */
export function useExportMoreTableInSheet(sheetConfig, filename) {
  const wb = XLSX.utils.book_new(); // 生成一个新的Excel文
  // eslint-disable-next-line guard-for-in,no-unused-vars
  for (const sheet in sheetConfig) {
    let xlsxData = []; // aoa_to_sheet方法需要的2d数组数据
    const { sheetBody, mergeRules, columnWidth } = sheetConfig[sheet]; // 每个工作表配置的sheetTitle, sheetBody
    sheetBody.map((sheetBodyEl) => {
      const headerArr = sheetBodyEl.type === 1 ? useHeaderByColumns(sheetBodyEl.columns) : sheetBodyEl.type === 2 ? sheetBodyEl?.groupedHeader : []; // 表格header
      const bodyArr = useBodyByDataSource([1, 2].includes(sheetBodyEl.type) ? sheetBodyEl.dataSource : []); // 表格body
      const anyXlsxData = [1, 2].includes(sheetBodyEl.type) ? [...headerArr, ...bodyArr] : [...sheetBodyEl?.anyXlsxData]; // 合并每个表格对象的数组,
      xlsxData = xlsxData.concat(anyXlsxData);
    });
    console.log('xlsxData>>>>>>>>', xlsxData);
    if (!xlsxData) throw new Error(); // xlsxData防错
    let workSheet = XLSX.utils.aoa_to_sheet(xlsxData); // xlsx数据转成xlsx工作表
    workSheet['!ref'] = `A1:AI${xlsxData.length}`; // 表格的合并范围
    workSheet['!merges'] = mergeRules || []; // 设置合并规则
    workSheet['!cols'] = columnWidth || []; // 列宽度
    // 如果传入callback操作style
    const callback = sheetConfig[sheet].callback ? sheetConfig[sheet].callback : () => workSheet;
    // 接受自定义处理过后的workSheet对象，赋值给原来地workSheet对象
    workSheet = callback(workSheet);
    XLSX.utils.book_append_sheet(wb, workSheet, sheet); // 生成Excel表格
  }
  XLSX.writeFile(wb, filename.indexOf('.xls') !== -1 ? filename : `${filename}.xlsx`, {
    bookType: 'xlsx',
    bookSST: true,
    type: 'array',
  }); // 最后一步书写文档，并且强制让浏览器下载
}

/**
 * 转dataSource到xlsx导出数据
 * @param key getTableKeyAndTitle返回的keys数组
 * @param jsonData 列表dataSource
 * @param enumMap?: { Array }
 * @returns {[[*],[*],[*]]}
 */
// eslint-disable-next-line camelcase
function jsonToArray(key, jsonData, enumMap = []) {
  return jsonData?.map((v) =>
    key.map((j) => {
      if (enumMap && enumMap[j]) {
        if (typeof enumMap[j] === 'function') {
          return enumMap[j](v[j]);
        }
        if (Array.isArray(enumMap[j])) {
          // eslint-disable-next-line no-unused-vars
          for (const item of enumMap[j]) {
            if (item.value === v[j]) {
              return item.label;
            }
          }
        }
      } else {
        return v[j];
      }
    }),
  );
}
/**
 * @param {T[]} Columns 传递进来表的Columns
 * @param {string} [action="action"] //要跳过的字段，如操作 "action" 只能传递进来一个字符串
 * @return {{keys: Array, titles: Array}}  keys: 列的key数组，titles：列的title数组
 * @description 在前台导出表格的时候，通过表格Columns获取要导出的key和title
 */
function getTableKeyAndTitle(Columns, action = 'action') {
  const KeyT = [];
  const TitleT = [];
  // eslint-disable-next-line no-unused-vars
  for (const x in Columns) {
    if (Columns[x]?.key?.toString() == action) {
      // eslint-disable-next-line no-continue
      continue;
    }
    KeyT.push(Columns[x]?.key?.toString()); // 获取key数组
    TitleT.push(Columns[x]?.title); // 获取title数组
  }
  return {
    keys: KeyT,
    titles: TitleT,
  };
}

/**
 * 导出excel通用方法，只需要传入dataSource和columns，自动处理数据，基于数据导出excel，可以传多个sheet的配置
 * @desc sheet: 工作表名，data：表格的dataSource，columns: 表格的columns，action：columns内要跳过导出的列key, callback: 接受工作表对象，返回操作后的工作表对象
 * @param sheetConfig { {sheet: {data: Array, columns: Array, action?: string, callback?: (workSheet) => workSheet}} }
 * @param filename 文件名
 */
export function useExportExcel(sheetConfig, filename) {
  const wb = XLSX.utils.book_new(); // 生成一个新的Excel文档
  // eslint-disable-next-line guard-for-in,no-unused-vars
  for (const sheet in sheetConfig) {
    const { keys, titles } = getTableKeyAndTitle(sheetConfig[sheet].columns, sheetConfig[sheet].action ?? 'action');
    // 未处理的data
    const unDisposeData = sheetConfig[sheet].data;
    // 已处理的data 转成需要的数组形式
    const disposedData = jsonToArray(keys, unDisposeData);
    // 插入title
    disposedData.unshift(titles);
    // workSheet对象
    let ws = XLSX.utils.aoa_to_sheet(disposedData); // XLSX.utils.aoa_to_sheet---将JS数据数组的数组转换为工作表
    // 如果传入callback操作style
    const callback = sheetConfig[sheet].callback ? sheetConfig[sheet].callback : () => ws;
    // 接受自定义处理过后的workSheet对象，赋值给原来地workSheet对象
    ws = callback(ws);
    XLSX.utils.book_append_sheet(wb, ws, sheet); // 生成Excel表格
  }
  XLSX.writeFile(wb, `${filename}.xlsx`); // 最后一步书写文档，并且强制让浏览器下载
}
